﻿
using System;
using System.Security.Cryptography;
using System.Text;
using Microsoft.Win32;

namespace Okarito
{
    public static class AuthenticationUtility
    {
        /// <summary>
        /// Retrieves FogBugz authentication credentials from a standard location in the registry.
        /// </summary>
        /// <param name="serverUri">The server URI.</param>
        /// <param name="userName">The FogBugz user name.</param>
        /// <param name="password">The FogBugz password</param>
        /// <returns><c>true</c> if the credentials were retrieved; otherwise <c>false</c>.</returns>
        public static bool GetCredentials(out Uri serverUri, out string userName, out string password)
        {
            using (RegistryKey credentialsKey = Registry.CurrentUser.CreateSubKey(@"Software\Okarito\Credentials"))
            {
                string server = (string) credentialsKey.GetValue(ServerValueName);
                string localUserName = (string) credentialsKey.GetValue(UserNameValueName);
                string encodedPassword = (string) credentialsKey.GetValue(PasswordValueName);

                if (server != null && Uri.TryCreate(server, UriKind.Absolute, out serverUri) && localUserName != null && encodedPassword != null)
                {
                    userName = localUserName;
                    password = UnprotectString(encodedPassword);
                    return true;
                }
                else
                {
                    serverUri = null;
                    userName = null;
                    password = null;
                    return false;
                }
            }
        }

        /// <summary>
        /// Saves FogBugz authentication credentials to a standard location in the registry.
        /// </summary>
        /// <param name="serverUri">The server URI.</param>
        /// <param name="userName">The FogBugz user name.</param>
        /// <param name="password">The FogBugz password</param>
        public static void SaveCredentials(Uri serverUri, string userName, string password)
        {
            using (RegistryKey credentialsKey = Registry.CurrentUser.CreateSubKey(@"Software\Okarito\Credentials"))
            {
                credentialsKey.SetValue(ServerValueName, serverUri.AbsoluteUri);
                credentialsKey.SetValue(UserNameValueName, userName);
                credentialsKey.SetValue(PasswordValueName, ProtectString(password));
            }
        }

        // Protects a string (for the current user) with the Data Protection API.
        private static string ProtectString(string unprotectedString)
        {
            // encode in UTF-8
            byte[] encodedString = Encoding.UTF8.GetBytes(unprotectedString);

            // protect with DPAPI
            byte[] protectedData = ProtectedData.Protect(encodedString, null, DataProtectionScope.CurrentUser);

            // convert to Base64
            return Convert.ToBase64String(protectedData);
        }

        // Protects a string (protected with ProtectStrnig for the current user) with the Data Protection API.
        private static string UnprotectString(string protectedString)
        {
            // decode from Base64
            byte[] protectedData;
            try
            {
                protectedData = Convert.FromBase64String(protectedString);
            }
            catch (FormatException e)
            {
                throw new ArgumentException("'protectedData' is not a valid Base64 string.", "protectedString", e);
            }

            // unprotect the data
            byte[] encodedString = ProtectedData.Unprotect(protectedData, null, DataProtectionScope.CurrentUser);

            // convert the UTF-8 encoded text to a string
            return Encoding.UTF8.GetString(encodedString);
        }

        const string ServerValueName = "Server";
        const string UserNameValueName = "UserName";
        const string PasswordValueName = "Password";
    }
}
